﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using Debug;
using Microsoft.Xna.Framework.Graphics;

namespace Kristall
{
    [Serializable]
    public class Options
    {
        [DescriptionAttribute("Determines if the game should be in window or fullscreen moed, required video restart")]
        public bool gfx_fullscreen { get; set; }

        [DescriptionAttribute("Width of the screen in pixels, required video restart")]
        public int gfx_screenwidth { get; set; }

        [DescriptionAttribute("Height of the screen in pixels, required video restart")]
        public int gfx_screenheight { get; set; }

        [DescriptionAttribute("Show or hide mouse")]
        public bool show_mouse { get; set; }

        [DescriptionAttribute("Sound volume")]
        float _sound_volume = 0.15f;
        public float sound_volume
        {
            get
            {
                return _sound_volume;
            }
            set
            {
                _sound_volume = MathHelper.Clamp(value, 0, 1);
                Kristall.SoundManager.SetCategoryVolume(_sound_volume, "Global");
            }
        }

        [DescriptionAttribute("Name of the options file, this is readonly")]
        public string cfg_name
        {
            get;
            set;
        }

        [DescriptionAttribute("Show or hide debug information")]
        public bool debug { get; set; }

        float _camera_scale = 1.0f;
        [DescriptionAttribute("Set the scale (zoom) of the camera")]
        public float camera_scale
        {
            get
            {
                return _camera_scale;
            }
            set
            {
                _camera_scale = value;

                if (_camera_scale < 0.1f)
                    _camera_scale = 0.1f;
            }
        }

        public float follow_light { get; set; }

        /*public Blend csb { get; set; }

        public Blend cdb { get; set; }

        public Blend asb { get; set; }

        public Blend adb { get; set; }*/

        public bool lights { get; set; }

        public float fl_size { get; set; }

        public float stun_time { get; set; }

        public float fl_ambient { get; set; }

        [DescriptionAttribute("Determines how fast the player regenerates health")]
        public float regen { get; set; }

        public bool fl_drawlights { get; set; }

        public float drainspeed { get; set; }

        public float ground_drag { get; set; }

        public float air_drag { get; set; }

        public float max_speed { get; set; }

        public float jump_vel { get; set; }

        public float jump_time { get; set; }

        public float eo_damping { get; set; }

        public float eo_stiffness { get; set; }

        public float eo_mass { get; set; }

        public float e_flying_speed { get; set; }

        public int nudge_distance { get; set; }

        public float player_firecooldown { get; set; }

        private Options()
        {
            sound_volume = 0.15f;
            
            camera_spring = true;
            camera_mass = 50.0f;

            gfx_fullscreen = false;
            gfx_screenheight = 768;
            gfx_screenwidth = 1024;

            player_speed = 13000f;

            follow_light = 0.8f;

            debug = true;

            ambient_light = 0;
            destination_blend = Blend.SourceColor;
            source_blend = Blend.DestinationColor;

            fl_size = 1.0f;
            fl_ambient = 0;
            stun_time = 0.5f;
            regen = 1 / 50f;

            drainspeed = 2f;

            max_speed = 500f;
            player_speed = 2000f;
            air_drag = 0.97f;
            ground_drag = 0.9f;

            jump_vel = -3500f;
            jump_time = 0.35f;

            nudge_distance = 36;

            player_firecooldown = 0.15f;

            fl_intensity = 1.0f;

            cfg_name = "options.xml";
        }

        public void Save()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Options));
            FileStream fs = new FileStream(cfg_name, FileMode.Create);
            serializer.Serialize(fs, this);
            fs.Close();

            Kristall.Echo(DebugConsole.CCCyan + "Config saved to: " + cfg_name);
        }

        public void Save(string fileName)
        {
            cfg_name = fileName;
            Save();
        }

        public static Options Load(string fileName = "options.xml")
        {
            if (File.Exists(fileName))
            {
                FileStream fs = new FileStream(fileName, FileMode.Open);
                XmlSerializer serializer = new XmlSerializer(typeof(Options));
                Options options = (Options)serializer.Deserialize(fs);
                fs.Close();

                Kristall.Echo(DebugConsole.CCCyan + options.cfg_name + " was loaded succeessfully!");

                return options;
            }
            else
            {
                Kristall.Echo(DebugConsole.CCRed + fileName + " was not found, using default config!");
            }

            return new Options();
        }

        [DescriptionAttribute("Determines if the camera should move with a spring-effect or not")]
        public bool camera_spring { get; set; }

        [DescriptionAttribute("Sets the mass of the camera")]
        public float camera_mass { get; set; }

        [DescriptionAttribute("Set the speed of the player")]
        public float player_speed { get; set; }

        public Blend source_blend { get; set; }

        public Blend destination_blend { get; set; }

        public float ambient_light { get; set; }

        public static Blend parseBlend(string s)
        {
            int result;
            if (int.TryParse(s, out result))
            {
                return (Blend)result;
            }
            return Blend.One;
        }

        public float sound_depth { get; set; }

        public float fl_intensity { get; set; }
    }
}
